
package com.sx.core.page;

import org.springframework.core.convert.converter.Converter;

import java.util.List;


/**
 * TODO: DOCUMENT ME!
 *
 * @author   <a href="mailto:lihao@ozstrategy.com">Hao Li</a>
 * @version  03/27/2017 17:08
 */
public class PageImpl<T> extends Chunk<T> implements Page<T> {
  //~ Static fields/initializers ---------------------------------------------------------------------------------------

  private static final long serialVersionUID = 867755909294344406L;

  //~ Instance fields --------------------------------------------------------------------------------------------------

  private final Pageable pageable;

  private final long total;

  //~ Constructors -----------------------------------------------------------------------------------------------------

  /**
   * Creates a new PageImpl object.
   *
   * @param  content  List
   */
  public PageImpl(List<T> content) {
    this(content, null, (null == content) ? 0 : content.size());
  }

  /**
   * Creates a new PageImpl object.
   *
   * @param  content   List
   * @param  pageable  Pageable
   * @param  total     long
   */
  public PageImpl(List<T> content, Pageable pageable, long total) {
    super(content, pageable);

    this.pageable = pageable;
    this.total    =
      (!content.isEmpty() && (pageable != null) && ((pageable.getOffset() + pageable.getPageSize()) > total))
      ? (pageable.getOffset() + content.size()) : total;
  }

  //~ Methods ----------------------------------------------------------------------------------------------------------

  /**
   * @see  Chunk#equals(Object)
   */
  @Override public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }

    if (!(obj instanceof PageImpl<?>)) {
      return false;
    }

    PageImpl<?> that = (PageImpl<?>) obj;

    return (this.total == that.total) && super.equals(obj);
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Page#getTotalElements()
   */
  @Override public long getTotalElements() {
    return total;
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Page#getTotalPages()
   */
  @Override public int getTotalPages() {
    return (getSize() == 0) ? 1 : (int) Math.ceil((double) total / (double) getSize());
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Chunk#hashCode()
   */
  @Override public int hashCode() {
    int result = 17;

    result += 31 * (int) (total ^ (total >>> 32));
    result += 31 * super.hashCode();

    return result;
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#hasNext()
   */
  @Override public boolean hasNext() {
    return (getNumber() + 1) < getTotalPages();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Chunk#isLast()
   */
  @Override public boolean isLast() {
    return !hasNext();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#map(Converter)
   */
  @Override public <S> Page<S> map(Converter<? super T, ? extends S> converter) {
    return new PageImpl<S>(getConvertedContent(converter), pageable, total);
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Object#toString()
   */
  @Override public String toString() {
    String  contentType = "UNKNOWN";
    List<T> content     = getContent();

    if (content.size() > 0) {
      contentType = content.get(0).getClass().getName();
    }

    return String.format("Page %s of %d containing %s instances", getNumber() + 1, getTotalPages(), contentType);
  }
} // end class PageImpl
